/* @author: 	 Jeramie Hallyburton
 * @file:		 GameLoop.java
 * @date:		 12/09/2011
 * @description: Thread containing a loop for performing game updating and rendering cycles
 */
package mobiledev.project3.spaceinvaders;

import android.graphics.Canvas;
import android.util.Log;
import android.view.SurfaceHolder;

public class GameLoop extends Thread {
	private static final String TAG = GameLoop.class.getSimpleName();
	
	//the desired frames per second
	private static final int MAX_FPS = 60;
	//the max num of frames to be skipped to keep a constant speed
	private static final int MAX_FRAME_SKIPS = 5;
	//the frame period
	private final static int FRAME_PERIOD = 1000 / MAX_FPS;
	private boolean threadStarted;
	private boolean isRunning;
	
	private SurfaceHolder 		surfaceHolder;
	private SpaceInvadersView 	siView;
	
	
	public GameLoop( SurfaceHolder surfaceHolder, SpaceInvadersView siView ) {
		super();
		this.surfaceHolder = surfaceHolder;
		this.siView = siView;
	}
	
	public void setRunning( boolean isRunning ) {
		this.isRunning = isRunning;
	}
	
	@Override
	public void run() {
		Canvas canvas;
		Log.d( TAG, "Starting game loop" );
		
		long 	beginTime; 			//the time when the cycle began
		long 	timeDiff;  			//the time it took for the cycle to execute
		int 	sleepTime = 0; 		//milliseconds to sleep. it will be less than 0 if we are behind
		int 	framesSkipped; 		//the number of frames being skipped
		
		while( isRunning ) {
			canvas = null;
			//lock the canvas for exclusive drawing
			try {
				canvas = this.surfaceHolder.lockCanvas();
				synchronized ( surfaceHolder ) {
					beginTime = System.currentTimeMillis();
					framesSkipped = 0;
					
					//update game
					this.siView.update();
					
					//render game
					this.siView.render( canvas );
					
					//calculate how long the cycle took
					timeDiff = System.currentTimeMillis() - beginTime;
					
					//calculate the time to sleep
					sleepTime = (int)( FRAME_PERIOD - timeDiff );
					
					if( sleepTime > 0 ) {
						try {
							Thread.sleep( sleepTime );
						} catch( InterruptedException e ) {}
					}
					
					while( sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS ) {
						//catch up by updating without rendering
						this.siView.update();
						//add to the frameperiod to see if we're in the next frame
						sleepTime += FRAME_PERIOD;
						framesSkipped++;
					}
				}
			} catch ( Exception ex ) {
				
			} finally {
				//clean up canvas
				if( canvas != null )
					surfaceHolder.unlockCanvasAndPost( canvas );
			}
		}
	}

	public boolean isThreadStarted() {
		return threadStarted;
	}

	public void setThreadStarted(boolean threadStarted) {
		this.threadStarted = threadStarted;
	}
	

}
